package Mapeamento.QuadTree;

import GUI.Obstaculos;
import Planejamento.Caminho.Aresta;
import java.util.ArrayList;


/*
 * O No corresponde ao componente fundamental para a formaçao da arvore.
 * Tem como caracteristica a formaçao de 4 filhos para cada no, que representam as 4 regioes
 * da celula subdividida.
 * Como o No representa uma celula no mapeamento, possui como atributos os vertice para a localizaçao no mapa.
 * Cada No e definido quanto a sua ocupaçao como sendo livre, misto ou ocupado.
 * Para cada No foi inserido como atributo uma lista de celulas vizinhas, sendo possivel a formaçao de um grafo
 * para planejamento do caminho.
 *
 *      _____P1
 *     |     |
 *     |     |
 *     |     |
 *    P2-----
 */
public class No
{
   public int id;
   public Tipo tipo;
   public No pai;
   public No filho1;
   public No filho2;
   public No filho3;
   public No filho4;
   public Vertice p1, p2;
   public int flag = 0;
   
   public ArrayList<Aresta> vizinhoss;
   public boolean noFinal = false;
   public boolean noInicio = false;

   public double estimativa = Double.MAX_VALUE;
   public No precedente;
   public boolean aberto = true;
   public boolean perdido = false;



   // Construtor para qualquer No exceto a Raiz
   public No (int ident, Tipo t, No p,  Vertice p1, Vertice p2)
   {
        vizinhoss = new ArrayList<Aresta>();
        id = ident;
        tipo = t;
        pai = p;
        this.p1 = p1;
        this.p2 = p2;
   }
   // Construtor apenas para a Raiz
   public No(int ident, Tipo t, Vertice p1, Vertice p2)
   {
        id = ident;
        tipo = t;
        pai = null;
        this.p1 = p1;
        this.p2 = p2;
   }
   // Metodo para geraçao dos filhos de um No
   // Por parametro sao passados o id do ultimo No e o No que sera o pai
   // dos 4 Nos criados
   public int gerarFilhos(int id, No pai)
   {
        int temp = id+1;
        Vertice tp1, tp2;

        // Criaçao das sub-celulas
        // Defini-se primeiro os vertices p1,p2 que compoe cada celula

        //             __________p1(x,y)
        //             |          |
        //             |          |
        //             |          |
        //       (x,y)p2_________ |

        // Calculo para a definiçao dos vertices
        tp1 = new Vertice((((this.p1.x)/2)+(this.p2.x)/2), 0+this.p1.y);
        tp2 = new Vertice(0+this.p2.x, ((this.p2.y-this.p1.y)/2+this.p1.y));
        filho1 = new No(temp, Tipo.livre, pai, tp1, tp2);
        temp++;

        tp1 = new Vertice((this.p1.x-this.p2.x)+this.p2.x, 0+this.p1.y);
        tp2 = new Vertice(((this.p1.x)-this.p2.x)/2+this.p2.x, ((this.p2.y-this.p1.y)/2+this.p1.y));
        filho2 = new No(temp, Tipo.livre, pai, tp1, tp2);
        temp++;

        tp1 = new Vertice((((this.p1.x)/2)+(this.p2.x)/2), ((this.p2.y-this.p1.y)/2+this.p1.y));
        tp2 = new Vertice(0+this.p2.x, this.p2.y);
        filho3 = new No(temp, Tipo.livre, pai, tp1, tp2);
        temp++;

        tp1 = new Vertice(this.p1.x, ((this.p2.y-this.p1.y)/2)+this.p1.y);
        tp2 = new Vertice((this.p1.x-this.p2.x)/2+this.p2.x, this.p2.y);
        filho4 = new No(temp, Tipo.livre, pai, tp1, tp2);
        return temp;
   }

   public void classificar(Obstaculos obstaculos)
   {
        int tp = 0;

        // Verifica se possui algum obstaculos interno as celulas filhas.
        // Classifica as 4 novas regioes.

        // Celula 1
        tp =  obstaculos.classificaCelula(filho1.p2.x, filho1.p2.y, filho1.p1.x, filho1.p1.y);
        if(tp == -1)
        {
            //OCUPADO
            filho1.tipo = Tipo.ocupado;
        }else if(tp == 1)
        {
            //MISTO
            filho1.tipo = Tipo.misto;
        }else
            filho1.tipo = Tipo.livre;

        // Celula 2
        tp =  obstaculos.classificaCelula(filho2.p2.x, filho2.p2.y, filho2.p1.x, filho2.p1.y);
        if(tp == -1)
        {
            //OCUPADO
            filho2.tipo = Tipo.ocupado;
        }else if(tp == 1)
        {
            //MISTO
            filho2.tipo = Tipo.misto;
        }else
            filho2.tipo = Tipo.livre;

        // Celula 3
        tp =  obstaculos.classificaCelula(filho3.p2.x, filho3.p2.y, filho3.p1.x, filho3.p1.y);
        if(tp == -1)
        {
            //OCUPADO
            filho3.tipo = Tipo.ocupado;
        }else if(tp == 1)
        {
            //MISTO
            filho3.tipo = Tipo.misto;
        }else
            filho3.tipo = Tipo.livre;

        // Celula 4
        tp =  obstaculos.classificaCelula(filho4.p2.x, filho4.p2.y, filho4.p1.x, filho4.p1.y);
         if(tp == -1)
        {
            //OCUPADO
            filho4.tipo = Tipo.ocupado;
        }else if(tp == 1)
        {
            //MISTO
            filho4.tipo = Tipo.misto;
        }else
            filho4.tipo = Tipo.livre;
   }


   // Identificar o proximo filho para dar continuidade na verificaçao da arvore
   public No proximoFilho(No anterior)
   {
        No fim;

        if(anterior == filho1)
            return filho2;
        else if(anterior == filho2)
            return filho3;
        else if(anterior == filho3)
            return filho4;
        else if(anterior == filho4)
        {
            // Volta para o pai
            // Verifica se retornou a raiz do grafo. Se sim, retorna um nodo
            // que ira finaliza a verificaçao da arvore.
            if(this.id != 1)
                return pai.proximoFilho(this);
            else
                return fim = new No(-1, Tipo.ocupado, null, null);
        }
        else
        {
            System.out.println("ERRO!!!");
            return null;
        }
   }

    public int getRotulo() {
        return id;
    }

    public boolean isNoFinal() {
        return noFinal;
    }

    public boolean isNoInicio() {
        return noInicio;
    }

    public void setNoFinal(boolean noFinal) {
        this.noFinal = noFinal;
    }

    public void setNoInicio(boolean noInicio) {
        this.noInicio = noInicio;
    }

}
